package com.kamkor.interviewer.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.RootPanel;
import com.kamkor.interviewer.client.event.CreateInterviewEvent;
import com.kamkor.interviewer.client.event.CreateInterviewEventHandler;
import com.kamkor.interviewer.client.event.MergeInterviewEvent;
import com.kamkor.interviewer.client.event.MergeInterviewEventHandler;
import com.kamkor.interviewer.client.event.SaveAllEvent;
import com.kamkor.interviewer.client.event.SaveAllEventHandler;
import com.kamkor.interviewer.client.presenter.AnswerInterviewPresenter;
import com.kamkor.interviewer.client.presenter.CreateInterviewPresenter;
import com.kamkor.interviewer.client.presenter.EditInterviewPresenter;
import com.kamkor.interviewer.client.presenter.InterviewInfoPresenter;
import com.kamkor.interviewer.client.presenter.MainPresenter;
import com.kamkor.interviewer.client.presenter.MergeInterviewPresenter;
import com.kamkor.interviewer.client.presenter.Presenter;
import com.kamkor.interviewer.client.presenter.Saveable;
import com.kamkor.interviewer.client.security.Authentication;
import com.kamkor.interviewer.client.view.AnswerInterviewView;
import com.kamkor.interviewer.client.view.CreateInterviewView;
import com.kamkor.interviewer.client.view.EditInterviewView;
import com.kamkor.interviewer.client.view.InterviewInfoView;
import com.kamkor.interviewer.client.view.MainView;
import com.kamkor.interviewer.client.view.MergeInterviewView;
import com.kamkor.interviewer.shared.UserDetails;
import com.kamkor.interviewer.shared.InterviewDetails;

/**
 * Controls application. Handles user history and application events. 
 * Creates presenters and calls go on them.
 * 
 * @author kamkor
 *
 */
public class AppController implements Presenter, ValueChangeHandler<String> {
	private final HandlerManager eventBus;
	private final InterviewServiceAsync interviewRpcService;
	private final Authentication interviewerAuthentication;
	private final Authentication interviewedAuthentication;
	private HasWidgets container;	
	private Presenter currentPresenter;

	public AppController(HandlerManager eventBus, InterviewServiceAsync interviewRpcService, 
			Authentication interviewerAuthentication, Authentication interviewedAuthentication) {			
				this.eventBus = eventBus;
				this.interviewRpcService = interviewRpcService;	
				this.interviewerAuthentication = interviewerAuthentication;
				this.interviewedAuthentication = interviewedAuthentication;
				bind();
	}
	
	private void bind() {		
		History.addValueChangeHandler(this);
		
		eventBus.addHandler(CreateInterviewEvent.TYPE, new CreateInterviewEventHandler() {
			@Override
			public void onCreateInterview(CreateInterviewEvent event) {
				doCreateInterview(event.getInterviewDetails());										
			}			
		});
		
		eventBus.addHandler(MergeInterviewEvent.TYPE, new MergeInterviewEventHandler() {		
			public void onMergeInterview(MergeInterviewEvent event) {
				doMergeInterview(event.getUserDetails());			
			}			
		});
		
		eventBus.addHandler(SaveAllEvent.TYPE, new SaveAllEventHandler() {
			@Override
			public void onSaveAll(SaveAllEvent event) {
				if (currentPresenter instanceof Saveable) {
					((Saveable) currentPresenter).doSaveAll();
				}
			}			
		});
	}
	
	private void doCreateInterview(InterviewDetails interviewDetails) {
		LoadingIndicator.loadingStarted(Interviewer.constants.loading());
		interviewRpcService.createInterview(interviewDetails, new AsyncCallback<UserDetails>() {			
			@Override
			public void onSuccess(UserDetails details) {		
				LoadingIndicator.loadingFinished();	
				doCreateInterview(details.getId(), details.getAdminKey(), details.getUserKey());								
			}			
			@Override
			public void onFailure(Throwable caught) {
				LoadingIndicator.loadingFinished();	
			}
		});				
	}
	
	private void doCreateInterview(Long interviewId, Long adminKey, Long userKey) {
		History.newItem("interviewInfo&i="+ interviewId +"&k="+ adminKey +"&u="+ userKey);
	}
	
	private void doMergeInterview(UserDetails userDetails) {
		History.newItem("mergeInterview&i=" + userDetails.getId() +"&k="+ userDetails.getAdminKey());
	}
	
	@Override
	public void onValueChange(ValueChangeEvent<String> event) {
		String token = event.getValue();	
			
		if(token != null) {
			Presenter presenter = null;
			
			if(token.equals("main")) {
				presenter = new MainPresenter(new MainView());				
			} else if(token.equals("newInterview")) {				
				presenter = new CreateInterviewPresenter(new CreateInterviewView(), eventBus);			
			} else if(token.matches("interviewInfo&i=\\d+&k=\\d+&u=\\d+")) { // interviewInfo&i={one or more digits}&a={one or more digits}		
				final UserDetails ud = parseUserDetails(token);	
				presenter = new InterviewInfoPresenter(interviewRpcService, new InterviewInfoView(), eventBus, ud.getId(), ud.getAdminKey(), ud.getUserKey(), interviewerAuthentication);							
			} else if(token.matches("editInterview&i=\\d+&k=\\d+")) {
				final UserDetails ud = parseUserDetails(token);	
				presenter = new EditInterviewPresenter(interviewRpcService, new EditInterviewView(), eventBus, 
						ud.getId(), ud.getAdminKey(), interviewerAuthentication);				
			} else if(token.matches("mergeInterview&i=\\d+&k=\\d+")) {				
				final UserDetails ud = parseUserDetails(token);
				presenter = new MergeInterviewPresenter(interviewRpcService, new MergeInterviewView(), eventBus, 
						ud.getId(), ud.getAdminKey(), interviewerAuthentication);				
			} else if(token.matches("answerInterview&i=\\d+&k=\\d+")) {
				final UserDetails ud = parseUserDetails(token);	
				presenter = new AnswerInterviewPresenter(interviewRpcService, new AnswerInterviewView(), eventBus, 
						ud.getId(), ud.getAdminKey(), interviewedAuthentication);
			}
			
			if(presenter != null) {
				this.currentPresenter = presenter;
				presenter.go(container);
			}
			
		}		
	}
	
	/**
	 * Function assumes that k is the last parameter in token.
	 * 
	 * @param token historyToken that contains i and k parameters.
	 * @return {@link UserDetails} with parsed i (interview id) and k (key)
	 */
	private UserDetails parseUserDetails(String token)  {
		final String idArg = "i=";		
		final int idIndex = token.indexOf(idArg);
		
		final String adminKeyArg = "&k=";
		final int adminKeyIndex = token.indexOf(adminKeyArg);	
		
		final String userKeyArg = "&u=";
		final int userKeyIndex = token.indexOf(userKeyArg);

		final Long interviewId = Long.parseLong(token.substring(idIndex + idArg.length(), adminKeyIndex));	
		
		// if there is &u= arg:
		if (userKeyIndex != -1) {
			final Long adminKey = Long.parseLong(token.substring(adminKeyIndex + adminKeyArg.length(), userKeyIndex));
			final Long userKey = Long.parseLong(token.substring(userKeyIndex + userKeyArg.length()));
			return new UserDetails(interviewId, adminKey, userKey);
		} else {
			final Long adminKey = Long.parseLong(token.substring(adminKeyIndex + adminKeyArg.length()));
			return new UserDetails(interviewId, adminKey);
		}
	}
	
	@Override
	public void go(HasWidgets container) {
		this.container = container;
		
		if("".equals(History.getToken())) {
			History.newItem("main");
		} else {
			History.fireCurrentHistoryState();
		}
	}
	

}
